$def with (commands, config_categs)

<link rel="stylesheet" href="/static/css/switch.css">

<style>
.apply_button, .apply_button_hidden {
	width: 100%;
	paddding: 10px;
	cursor: hand;
	margin-top: 10px;
}

.apply_button_hidden {
	display: none;
}

.config-panel {
	min-width:300px;
	width:45%;
	float:left;
	margin-right:2%;
	margin-left: 2%;
}

.command-item {
	cursor: hand;
	float: left;
	min-width:300px;
	width: 21%;
	height:60px;
	padding:10px;
	margin-right:15px;
	margin-bottom:15px;
}

.command-remove-button {
	text-align:center;
	position:absolute;
	font-weight:bold;
	width:25px;
	height:20px;
}

.command-item:hover,.command-remove-button:hover{
	border-color: #F68B0D;
}

.command-exec-pane {
	float: left;
	width: 10px;
	height: 100%;
	background-color: #F68B0D;
}

.command-desc-pane {
	float: right;
	width: 90%;
	margin-left:10px;
}

.command-name {
	font-size: large;
	font-weight:bold;
}

.command-desc {
	font-size: normal;
	font-style: italic;
	text-color: grey;
}

.command-resp {
	font-weight: bold;
}
</style>

<script>
var gId = 0;

dict_config = {
$for key, val in config_categs:
	"$key" : $("0x%x"%val["default"]),
};

function cmdExecuteWithParameters(id,command){

	//	Close the dialog if command clicked twice
	if( $$("#params-"+id).length != 0 )
	{
		$$("#params-"+id).dialog("close");		
		return;
	}

	var cmd_desc = $$("#" + id + " .command-desc").text();
	var cmd_name = $$("#" + id + " .command-name").text();
	var dialog_header = 
		'<div id="params-'+id+'" title="'+cmd_name+'">' +
		'<p>'+ cmd_desc +'</p>' +
		'<form>' +
			'<fieldset>';
			
	var dialog_footer = 
			'</fieldset>' +
		'</form>' +
		'</div>';
		
	var dialog_content = "";
		
	//	Get parameter list from command or url of command
	var search = -1;
	var end;
	var parameters = [];
	
	while( true ) {
		search = command.indexOf("#",search+1);
		if( search == -1 )
			break;
		
		//	End of parameter name
		end = command.indexOf("#",search+1);

		//	Add param to array
		parameters.push(command.substring(search+1,end));
		
		//	Jump over parameter
		search = end+1;
	}
	
	//	Construct contents of dialog
	for (var item in parameters) {
		dialog_content += 
			'<label for='+item+'>'+parameters[item]+'</label>' + 
			'<br>' + 
			'<input type="text" name="'+item+'" id="'+item+'" class="ui-widget-content ui-corner-all" style="width:100%;">' +
			'<br>';
	}

	function onRun() {
		var finalcmd = command;
		//	Replace each parameter with form value
		for (var item in parameters) {
			form = dialog.find("#"+item);
			finalcmd = finalcmd.replace("#" + parameters[item] + "#",form.prop("value"));
		}
		
		//	Execute modified command
		cmdExecuteDoPost(id,finalcmd);
	}
	
	function onRunAndClose()
	{
		onRun();
		dialog.dialog("close");
	}
		
	//	Insert dialog
	$$("body").after(
			dialog_header + 
			dialog_content + 
			dialog_footer );

	//	Construct JQuery dialog
	var dialog = $$("#params-"+id).dialog({
		  autoOpen: true,
		  height: 250 + 60 * parameters.length,
		  width: 500,
		  modal: false,
		  position: {my:"bottom",at:"top",of:"#"+id},
		  buttons: {
			"Run": onRun,
			"Run & Close": onRunAndClose,
			Cancel: function() {
			  dialog.dialog( "close" );
			}
		  },
		  show: {
			effect: "blinds",
			duration: 300
		  },
		  close: function() {			
			dialog.remove();
		  }
		});

	event.preventDefault();
}
	
//
//	Submit command
//

function cmdExecuteDoPost(id,url) {
	var ctrl = $$("#" + id);
	var ctrl_state = ctrl.find(".command-exec-pane");
	var ctrl_response = ctrl.find("#response");
	
	//	Mark command in progress
	ctrl_response.text("In progress..");
	ctrl_state.css("background-color", "red");
	
	$$.get(url, function(data) {						
		ctrl_state.show();
		ctrl_state.css("background-color", "#F68B0D");
		ctrl_response.text(data);			
	});
}

function cmdExecute(id){
	var ctrl = $$("#" + id);
	var url = ctrl.attr('url');
	
	//	Check if it has any parameter symbol
	//	and execute the corresponding function
	
	if( url.indexOf("#") != -1 )
			cmdExecuteWithParameters(id,url);
	else	cmdExecuteDoPost(id,url);
}

//
//	Change function for each input element in configuration area
//

function onSwitchChanged(id) {
		
		var _this = $$("#"+id);
		
		// Get data from element
		var checked = _this.prop("checked");
		var categ =_this.attr('_categ');
		var bit = _this.attr('_bit');
			
		//	If checked, add bit else remove it
		if( checked )
				dict_config[categ] |= (1<<bit);
		else	dict_config[categ] &= ~(1<<bit);
		
		// Modify label to reflect flag change
		var label = $$("#"+categ+"-flags");
		label.html("0x" + dict_config[categ].toString(16));
		
		//	Insert or modify apply button
		var categ_div = label.parents("#" + categ + "-div");
		var apply = categ_div.children("#" + categ + "-apply")
		
		if( apply.length == 0 )
		{
			//	Insert apply button
			categ_div.
				append("<div id='"+categ+"-apply' class='ui-widget-content ui-corner-all apply_button_hidden'>Apply</div>");
				
			apply = categ_div.children("#" + categ + "-apply").show();
			apply.
				click( function() {
				
					//	Unbind click, destroy id so it can no longer be found
					apply.unbind("click").attr("id","__unused");
					
					// Inform user we've updated the value
					apply.text("Applying " + categ + " flags");
					apply.addClass('ui-state-highlight');

					// Execute command
					$$.get( "/command?cmd=" + categ + "=" + dict_config[categ].toString(16), function( data ) {					  
						if( data.indexOf("Failed:") == - 1 ) {						
							apply.text("Done (" + data + ")");
						} else {
							//apply.attr('value',data);
							apply.text(data);
							apply.removeClass('ui-state-highlight').addClass('ui-state-error');
						}
						
						setTimeout(function(){apply.hide("fast",function() {apply.remove()})}, 3000);
					});
					
					event.preventDefault();
				});
		}
}

//
//	Add new command 
//
function onSubmitCommand()
{
	var form = $$("#keros-new-command");
	var post_data = form.serialize();
	var response = form.find("#response");
	
	response.removeClass("ui-state-error");
	response.text("");
	
	$$.post("keros?" + post_data, function(data) {
		
		response.text(data);
				
		//	Reload if success
		if( data.indexOf("Failed") ==  -1 )		
			location.reload();
		else
			response.addClass("ui-state-error");
	});
	
	event.preventDefault();
}

function setupUserCommands()
{
	var user_cmds = $$("#user-commands .command-item");

	$$.each( user_cmds, function(index, cmd) {
		var cmd = $$(cmd);
		var cmdname = cmd.find(".command-name").text();
		var pos = cmd.position();
		
		//	Insert control and post remove command when done
		$$("<div class='ui-widget-header ui-corner-all command-remove-button' >X</div>")
			.appendTo(cmd)
				.css('left',pos.left + cmd.outerWidth() - 25 - 8)
				.css('top',pos.top + 40)
				.on("click",function(){
					$$.post("keros?rmcmd="+cmdname, function(data){
						if( data.indexOf("Failed") != -1 )
							alert(data);
						else
							location.reload();
							
						event.preventDefault();
					});
				});				
	});
}

</script>

<div id="configuration">
<h3>Configuration:</h3>

$for categ, val in config_categs:
	<div class="config-panel" >
		<h4 class="ui-widget-header" style="padding:5px;" id="$(categ)-div">$val["name"]:
			<div style="float:right;"><strong id="$(categ)-flags">$("0x%x" % val['default'])</strong></div>
		</h5>
		<table class="ui-widget-content ui-corner-all" style="width:100%;">
		$for bit, name in val["bits"].iteritems():
			<tr>
				<td style="width:100%;">$name</td><td>
					<div class="onoffswitch">
						<input type="checkbox" name="onoffswitch" class="onoffswitch-checkbox" 
							id="onoff$('%s_%s'%(categ,bit))" _categ="$categ" _bit="$bit" $('checked' if val['default'] & (1<<int(bit)) else '')
							onchange="onSwitchChanged(this.id)">
						<label class="onoffswitch-label" for="onoff$('%s_%s'%(categ,bit))">
							<span class="onoffswitch-inner"></span>
							<span class="onoffswitch-switch"></span>
						</label>
					</div>
				</td>
			</tr>
		</table>		
	</div>	
</div>

<div style="clear:both;"></div>

<h3>Commands:</h3>

$for group, cmds in commands:
	$if group == "User":
		<div id="user-commands">
	<h4>$group</h4>
	$for cmd in cmds:
		<div class="command-item ui-widget-content ui-corner-all" onclick="cmdExecute(this.id)" id="cmd-$(cmd[2].encode('hex'))" url="/command?cmd=$(cmd[2])">	
			<div class="command-desc-pane">
				<span class="command-name">$(cmd[0])</span><br>
				<span class="command-desc">$(cmd[1])</span><br>
				<span id="response" class="command-resp"></span>				
			</div>
			<div class="command-exec-pane"></div>			
		</div>
	<div style="clear:both;"></div>
	$if group == "User":
		</div>

<script>
	setupUserCommands();
</script>
	
	
<h3>Add new command:</h3>

<div style="width:350px;padding:10px;text-align:left;" class="ui-widget-content ui-corner-all">
	<form id="keros-new-command" method="post" enctype="multipart/form-data" onsubmit="onSubmitCommand()">
		<div style="width:100%;">
		Name: <input class="ui-widget-content" style="float:right;" type="edit" name="addcmd" value="Name"/>
		</div>
		<div style="clear:both;"></div>
		<div style="width:100%;">
		Desc: <input class="ui-widget-content" style="float:right;" type="edit" name="desc" value="Description"/>
		</div>
		<div style="clear:both;"></div>
		<div style="width:100%;">
		Command: <input class="ui-widget-content" style="float:right;" type="edit" name="cmd" value="Command"/>
		<div style="clear:both;"></div>
		</div>
		<br>
		<input class="ui-widget-content" style="width:100%" type="submit" value="Add"/>
		<p id="response"></p>
	</form>
</div>

<a href="#" onclick="javascript:cmdExecuteWithParameters('Baga a:#a# si b:#b# si c:#c#');">test dialog</a>